package com.sql.mysql.sharding.runnable;

import java.lang.reflect.Proxy;

import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.TransactionIsolationLevel;

import com.sql.mysql.sharding.session.ShardingSqlSessionFactory;
import com.sql.mysql.sharding.session.ShardingTransactionSqlSessionProxy;
import com.sql.mysql.sharding.threadlocal.ShardingThreadLocal;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class ShardingTransactionRunnable<T> extends BaseRunnable<T> {
	private static final boolean AUTO_COMMIT = false;// 事务类的,必须非自动提交

	protected SqlSession sqlSession = null;

	public ShardingTransactionRunnable() {
		sqlSession = ShardingSqlSessionFactory.getSqlSessionFactory().openSession(ExecutorType.SIMPLE, AUTO_COMMIT);
	}

	// 默认就不是自动提交
	public ShardingTransactionRunnable(TransactionIsolationLevel level) {
		sqlSession = ShardingSqlSessionFactory.getSqlSessionFactory().openSession(level);
	}

	public abstract T execute(SqlSession sqlSession) throws Exception;

	@Override
	public T run() throws Exception {
		// 前人不要影响我,全部清除
		ShardingThreadLocal.reset(true, true);
		try {
			// 需要做代理,目的为了做拦截
			// 对于暴露出去给业务用的session要做proxy
			T result = execute((SqlSession) Proxy.newProxyInstance(SqlSession.class.getClassLoader(),
					new Class[] { SqlSession.class }, //
					new ShardingTransactionSqlSessionProxy(sqlSession)));
			sqlSession.commit();
			return result;
		} catch (Exception e) {
			sqlSession.rollback();
			log.error("事务回滚");
			log.error(e.toString());
			throw e;
		} finally {
			if (null != sqlSession) {
				sqlSession.close();
			}
			// 我也不影响后人,全部清除
			ShardingThreadLocal.reset(true, true);
		}
	}

}
